#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "osal_io.h"
#include "osal_mem.h"
#include "osal_spinlock.h"
#include "gpio_core.h"
#include "gpio_if.h"

#define HDF_LOG_TAG imx6ull_gpio

#define LEDOFF 	0				/* 关灯 */
#define LEDON 	1				/* 开灯 */
 
/* 寄存器物理地址 */
#define CCM_CCGR1_BASE				(0X020C406C)	
#define SW_MUX_GPIO1_IO03_BASE		(0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE		(0X020E02F4)
#define GPIO1_DR_BASE				(0X0209C000)
#define GPIO1_GDIR_BASE				(0X0209C004)

struct imx6ull_gpio
{
    /* data */
    struct GpioCntlr cntlr;
    volatile unsigned char *regBase;
    uint32_t phyBase;
    uint32_t regStep;
};
void led_switch(uint16_t sta)
{
	uint32_t val = 0;
	if(sta == LEDON) {
		val = readl((void*)GPIO1_DR_BASE);
		val &= ~(1 << 3);	
		writel(val, (void*)GPIO1_DR_BASE);
	}else if(sta == LEDOFF) {
		val = readl((void*)GPIO1_DR_BASE);
		val|= (1 << 3);	
		writel(val, (void*)GPIO1_DR_BASE);
	}	
}
static int32_t IMX6ULL_GPIO_Write(struct GpioCntlr *cntlr, uint16_t local, uint16_t val)
{
    struct imx6ull_gpio *hcntlr = NULL;

    if (cntlr == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }
    hcntlr = (struct imx6ull_gpio *)cntlr;//将cntlr这个指针强制转换成struct imx6ull_gpio *类型的指针
    //结构体对象地址与第一个成员地址的关系是相等的
    led_switch(val);
    return HDF_SUCCESS;
}
static int32_t IMX6ULL_GPIO_Read(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val)
{
        struct imx6ull_gpio *hcntlr = NULL;

    if (cntlr == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }
    hcntlr = (struct imx6ull_gpio *)cntlr;

    return HDF_SUCCESS;
}


static struct GpioMethod g_method ={
    .write=IMX6ULL_GPIO_Write,
    .read=IMX6ULL_GPIO_Read,
};
static int32_t IMX6ULL_GPIO_ReadDrs(struct imx6ull_gpio *hcntlr, const struct DeviceResourceNode *node)//获取hcs文件中的配置信息
{
    int32_t ret;
    struct DeviceResourceIface *drsOps = NULL;

    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (drsOps == NULL || drsOps->GetUint32 == NULL) {
        HDF_LOGE("%s: invalid drs ops!", __func__);
        return HDF_FAILURE;
    }

    ret = drsOps->GetUint32(node, "regBase", &hcntlr->phyBase, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read regBase fail!", __func__);
        return ret;
    }

    ret = drsOps->GetUint32(node, "regStep", &hcntlr->regStep, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read regStep fail!", __func__);
        return ret;
    }

    return HDF_SUCCESS;
}

static int32_t IMX6ULL_GPIO_Bind(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct imx6ull_gpio *hcntlr = NULL;
    HDF_LOGI("%s: Enter", __func__);
    if (device == NULL || device->property == NULL) {
        HDF_LOGE("%s: device or property is null!", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    hcntlr = (struct imx6ull_gpio *)OsalMemCalloc(sizeof(*hcntlr));
    if (hcntlr == NULL) {
        HDF_LOGE("%s: malloc hwdt fail!", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }

    ret = IMX6ULL_GPIO_ReadDrs(hcntlr, device->property);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read drs fail:%d", __func__, ret);
        OsalMemFree(hcntlr);
        return ret;
    }
dprintf("IMX6ULL_GPIO_Bind 1\n");
    hcntlr->regBase = OsalIoRemap(hcntlr->phyBase, hcntlr->regStep);//Remaps an I/O physical address to its virtual address.
    if (hcntlr->regBase == NULL) {
        HDF_LOGE("%s: ioremap regbase fail!", __func__);
        OsalMemFree(hcntlr);
        return HDF_ERR_IO;
    }
    dprintf("%x,%x,%x\n",hcntlr->regBase,hcntlr->regStep,hcntlr->phyBase);
dprintf("IMX6ULL_GPIO_Bind 2\n");
    hcntlr->cntlr.priv = (void *)device->property;
    hcntlr->cntlr.ops = &g_method;
    hcntlr->cntlr.device = device;
    hcntlr->cntlr.count=1;
    ret = GpioCntlrAdd(&hcntlr->cntlr);
    dprintf("%d\n",ret);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: err add watchdog:%d", __func__, ret);
        OsalIoUnmap((void *)hcntlr->regBase);
        OsalMemFree(hcntlr);
        return ret;
    }
    HDF_LOGI("%s: dev service %s init success!", __func__, HdfDeviceGetServiceName(device));
    dprintf("IMX6ULL_GPIO_Bind success\n");
    return HDF_SUCCESS;
}
static int32_t IMX6ULL_GPIO_Init(struct HdfDeviceObject *device)
{
    (void)device;
    return HDF_SUCCESS;
}

static void IMX6ULL_GPIO_Release(struct HdfDeviceObject *device)
{
    struct GpioCntlr *cntlr = NULL;
    struct imx6ull_gpio *hcntlr = NULL;

    HDF_LOGI("%s: enter", __func__);
    if (device == NULL) {
        return;
    }

    cntlr = GpioCntlrFromDevice(device);
    if (cntlr == NULL) {
        return;
    }
    GpioCntlrRemove(cntlr);

    hcntlr = (struct imx6ull_gpio *)cntlr;
    if (hcntlr->regBase != NULL) {
        OsalIoUnmap((void *)hcntlr->regBase);
        hcntlr->regBase = NULL;
    }
    OsalMemFree(hcntlr);
}

struct HdfDriverEntry g_gpioDriverEntry = {
    .moduleVersion = 1,
    .Bind = IMX6ULL_GPIO_Bind,
    .Init = IMX6ULL_GPIO_Init,
    .Release = IMX6ULL_GPIO_Release,
    .moduleName = "HDF_PLATFORM_GPIO",
};
HDF_INIT(g_gpioDriverEntry);
